const express = require('express');
const router = express.Router();
const pool = require('../db');
const bcrypt = require('bcryptjs');
const authMiddleware = require('../middleware/auth');
const { createLog } = require('../log');

// helper to verify a user's password (supports legacy MD5 and bcrypt)
async function verifyPasswordForUser(userId, plainPwd) {
  const [rows] = await pool.query('SELECT pwd FROM atb_user WHERE id = ?', [userId]);
  if (!rows || rows.length === 0) return { found: false, match: false };
  const currentHash = rows[0].pwd || '';
  if (/^[a-f0-9]{32}$/i.test(currentHash)) {
    const crypto = require('crypto');
    const md5 = crypto.createHash('md5').update(String(plainPwd)).digest('hex');
    return { found: true, match: md5 === currentHash };
  } else {
    const match = await bcrypt.compare(String(plainPwd), currentHash);
    return { found: true, match };
  }
}

// GET /api/users?page=1&limit=10
// returns { users: [...], total: number }
router.get('/users', authMiddleware, async (req, res) => {
  try {
    // Only create a 'view' log when the client explicitly requests logging.
    // Some front-end code may call this API in background on many pages; avoid noisy logs by
    // requiring a query flag like ?_log=1 or ?_log=true when the page is actually opened.
    if (req.query && (req.query._log === '1' || req.query._log === 'true')) {
      createLog(req, { message: '打开用户列表', tp: 'view' });
    }

    const page = Math.max(1, parseInt(req.query.page, 10) || 1);
    const limit = Math.max(1, parseInt(req.query.limit, 10) || 10);
    const offset = (page - 1) * limit;

    // Sorting: allow only specific fields to avoid SQL injection
    const allowedSorts = {
      user_name: 'u.user_name',
      alisa: 'u.alisa',
      role_id: 'u.role_id',
      hospital_name: 'h.hos_name',
      created: 'u.created',
      entry_date: 'u.entry_date'
    };

    const sortBy = typeof req.query.sort_by === 'string' ? req.query.sort_by : null;
    let sortOrder = typeof req.query.sort_order === 'string' ? req.query.sort_order.toLowerCase() : null;
    if (sortOrder !== 'asc' && sortOrder !== 'desc') sortOrder = null;

    let orderClause = 'u.created DESC'; // default
    if (sortBy && allowedSorts[sortBy]) {
      orderClause = `${allowedSorts[sortBy]} ${sortOrder === 'asc' ? 'ASC' : 'DESC'}`;
    }

    // join with atb_hospital to return hospital name
    const [rows] = await pool.query(
      `SELECT u.id, u.role_id, u.user_name, u.alisa, u.sex, u.hospital_id, h.hos_name AS hospital_name, u.entry_date, u.created, u.updated FROM atb_user u LEFT JOIN atb_hospital h ON u.hospital_id = h.id ORDER BY ${orderClause} LIMIT ? OFFSET ?`,
      [limit, offset]
    );

    const [countRows] = await pool.query('SELECT COUNT(*) AS total FROM atb_user');
    const total = (countRows && countRows[0] && countRows[0].total) ? countRows[0].total : 0;

    res.json({ users: rows, total });
  } catch (err) {
    console.error('Failed to fetch users:', err);
    res.status(500).json({ message: 'Server error' });
  }
});

// New: GET /api/users/check?user_name=...&alisa=...&exclude_id=...
// returns { user_name: boolean, alisa: boolean }
router.get('/users/check', authMiddleware, async (req, res) => {
  try {
    const { user_name, alisa } = req.query;
    const excludeId = req.query.exclude_id ? parseInt(req.query.exclude_id, 10) : null;
    const result = { user_name: false, alisa: false };

    if (!user_name && !alisa) return res.status(400).json({ message: 'user_name or alisa required' });

    if (user_name) {
      const params = [String(user_name)];
      let sql = 'SELECT id FROM atb_user WHERE user_name = ?';
      if (excludeId) { sql += ' AND id != ?'; params.push(excludeId); }
      const [rows] = await pool.query(sql, params);
      if (rows && rows.length > 0) result.user_name = true;
    }

    if (alisa) {
      const params = [String(alisa)];
      let sql = 'SELECT id FROM atb_user WHERE alisa = ?';
      if (excludeId) { sql += ' AND id != ?'; params.push(excludeId); }
      const [rows] = await pool.query(sql, params);
      if (rows && rows.length > 0) result.alisa = true;
    }

    res.json(result);
  } catch (err) {
    console.error('Failed to check user uniqueness:', err);
    res.status(500).json({ message: 'Server error' });
  }
});

// POST /api/users
router.post('/users', authMiddleware, async (req, res) => {
  try {
    const { user_name, pwd, role_id, alisa, sex, hospital_id, entry_date } = req.body;
    if (!user_name || !pwd) return res.status(400).json({ message: 'user_name and pwd required' });

    // check uniqueness
    const [urows] = await pool.query('SELECT id FROM atb_user WHERE user_name = ?', [user_name]);
    if (urows && urows.length > 0) return res.status(409).json({ message: '用户名已存在', field: 'user_name' });

    if (alisa) {
      const [arows] = await pool.query('SELECT id FROM atb_user WHERE alisa = ?', [alisa]);
      if (arows && arows.length > 0) return res.status(409).json({ message: '昵称已存在', field: 'alisa' });
    }

    const hashed = await bcrypt.hash(pwd, 10);
    const [result] = await pool.query(
      'INSERT INTO atb_user (user_name, pwd, role_id, alisa, sex, hospital_id, entry_date, created) VALUES (?, ?, ?, ?, ?, ?, ?, NOW())',
      [user_name, hashed, role_id || null, alisa || '', sex || null, hospital_id || null, entry_date || null]
    );

    const insertId = result.insertId;
    const [rows] = await pool.query('SELECT u.id, u.role_id, u.user_name, u.alisa, u.sex, u.hospital_id, h.hos_name AS hospital_name, u.entry_date, u.created, u.updated FROM atb_user u LEFT JOIN atb_hospital h ON u.hospital_id = h.id WHERE u.id = ?', [insertId]);

    // log creation (omit pwd)
    createLog(req, { message: `新增用户 ${user_name}`, tp: 'create', obj_json: JSON.stringify(rows[0] || { id: insertId, user_name }) });

    res.status(201).json({ user: rows[0] });
  } catch (err) {
    console.error('Failed to create user:', err);
    res.status(500).json({ message: 'Server error' });
  }
});

// PUT /api/users/:id
router.put('/users/:id', authMiddleware, async (req, res) => {
  try {
    const id = parseInt(req.params.id, 10);
    if (isNaN(id)) return res.status(400).json({ message: 'Invalid user id' });

    const { pwd, role_id, alisa, sex, hospital_id, oldPwd } = req.body;
    const fields = [];
    const params = [];

    // check alisa uniqueness when provided
    if (typeof alisa !== 'undefined') {
      const [arows] = await pool.query('SELECT id FROM atb_user WHERE alisa = ? AND id != ?', [alisa, id]);
      if (arows && arows.length > 0) return res.status(409).json({ message: '昵称已存在', field: 'alisa' });
    }

    // normalize requester identity
    const requesterId = req.user && Number(req.user.id);
    const requesterRole = req.user && Number(req.user.role_id);
    const isAdmin = requesterRole === 1;
    const isSelf = requesterId === id;

    // If pwd is being changed, enforce permissions and old password verification
    if (typeof pwd !== 'undefined' && pwd !== null && String(pwd) !== '') {
      // only allow change when: the requester is the same user (id) OR requester is admin (role_id === 1)
      if (!isSelf && !isAdmin) {
        return res.status(403).json({ message: '没有权限修改此用户的密码' });
      }

      // if requester is the same user (and not admin), require oldPwd and verify it
      if (isSelf && !isAdmin) {
        if (!oldPwd) return res.status(400).json({ message: '旧密码必填' });
        const ver = await verifyPasswordForUser(id, oldPwd);
        if (!ver.found) return res.status(404).json({ message: 'User not found' });
        if (!ver.match) {
          // log failed attempt
          try { createLog(req, { message: `修改密码失败-旧密码不正确 user_id=${id}`, tp: 'security', obj_json: JSON.stringify({ user_id: id }) }); } catch(e){}
          return res.status(401).json({ message: '旧密码不正确' });
        }
      }

      // Prevent setting the new password equal to the current password
      // This works for both self-change and admin-change: compare new pwd against stored hash
      const sameCheck = await verifyPasswordForUser(id, pwd);
      if (!sameCheck.found) return res.status(404).json({ message: 'User not found' });
      if (sameCheck.match) {
        try { createLog(req, { message: `修改密码失败-新旧密码相同 user_id=${id}`, tp: 'security', obj_json: JSON.stringify({ user_id: id }) }); } catch(e){}
        return res.status(400).json({ message: '新密码不能与旧密码相同' });
      }

      // all good -> hash new password and include in update
      const hashed = await bcrypt.hash(pwd, 10);
      fields.push('pwd = ?');
      params.push(hashed);
    }

    if (typeof role_id !== 'undefined') { fields.push('role_id = ?'); params.push(role_id); }
    if (typeof alisa !== 'undefined') { fields.push('alisa = ?'); params.push(alisa); }
    if (typeof sex !== 'undefined') { fields.push('sex = ?'); params.push(sex); }
    if (typeof hospital_id !== 'undefined') { fields.push('hospital_id = ?'); params.push(hospital_id); }

    if (fields.length === 0) return res.status(400).json({ message: 'No fields to update' });

    // set updated timestamp
    fields.push('updated = NOW()');

    params.push(id);
    const sql = `UPDATE atb_user SET ${fields.join(', ')} WHERE id = ?`;
    await pool.query(sql, params);

    const [rows] = await pool.query('SELECT u.id, u.role_id, u.user_name, u.alisa, u.sex, u.hospital_id, h.hos_name AS hospital_name, u.entry_date, u.created, u.updated FROM atb_user u LEFT JOIN atb_hospital h ON u.hospital_id = h.id WHERE u.id = ?', [id]);

    // log update
    createLog(req, { message: `编辑用户 id=${id}`, tp: 'update', obj_json: JSON.stringify(rows[0] || { id }) });

    res.json({ user: rows[0] });
  } catch (err) {
    console.error('Failed to update user:', err);
    res.status(500).json({ message: 'Server error' });
  }
});

// POST /api/users/:id/verify-password
router.post('/users/:id/verify-password', authMiddleware, async (req, res) => {
  try {
    const id = parseInt(req.params.id, 10);
    if (isNaN(id)) return res.status(400).json({ message: 'Invalid user id' });

    const { oldPwd } = req.body || {};
    if (!oldPwd) return res.status(400).json({ message: 'oldPwd required' });

    const requesterId = req.user && req.user.id;
    const requesterRole = req.user && req.user.role_id;
    // only allow when requester is the same user or admin
    if (requesterId !== id && requesterRole !== 1) {
      return res.status(403).json({ message: '没有权限执行此操作' });
    }

    const ver = await verifyPasswordForUser(id, oldPwd);
    if (!ver.found) return res.status(404).json({ message: 'User not found' });
    if (!ver.match) {
      try { createLog(req, { message: `验证旧密码失败 user_id=${id}`, tp: 'security', obj_json: JSON.stringify({ user_id: id }) }); } catch(e){}
      return res.status(401).json({ message: '旧密码不正确' });
    }

    res.json({ ok: true });
  } catch (err) {
    console.error('Failed to verify password:', err);
    res.status(500).json({ message: 'Server error' });
  }
});

// DELETE /api/users/:id
router.delete('/users/:id', authMiddleware, async (req, res) => {
  try {
    const id = parseInt(req.params.id, 10);
    if (isNaN(id)) return res.status(400).json({ message: 'Invalid user id' });

    await pool.query('DELETE FROM atb_user WHERE id = ?', [id]);

    // log delete
    createLog(req, { message: `删除用户 id=${id}`, tp: 'delete', obj_json: JSON.stringify({ id }) });

    res.json({ ok: true });
  } catch (err) {
    console.error('Failed to delete user:', err);
    res.status(500).json({ message: 'Server error' });
  }
});

module.exports = router;
